package aviator;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import com.googlecode.aviator.FunctionMissing;
import com.googlecode.aviator.annotation.Function;
import com.googlecode.aviator.annotation.Ignore;
import com.googlecode.aviator.annotation.Import;
import com.googlecode.aviator.annotation.ImportScope;
import com.googlecode.aviator.runtime.JavaMethodReflectionFunctionMissing;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorFunction;
import com.googlecode.aviator.runtime.type.AviatorObject;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.min;
import org.junit.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.util.StringUtils;

import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.*;

/**
 * @program JavaBase
 * @description: 测试
 *  文档地址：https://www.yuque.com/boyan-avfmj/aviatorscript/cpow90
 * @author: zhanglu
 * @create: 2020-11-10 16:42:00
 */
@Slf4j
public class Test01 {

    /**
     * 自带函数，语法
     */
    @Test
    public void test01(){
        Expression compile = AviatorEvaluator.compile("for i in range(0, 10) {\n" +
                "  println(i);\n" +
                "}");
        compile.execute();
    }

    /**
     * 导入java静态方法
     */
    @Test
    public void test02() throws Exception {
        AviatorEvaluator.addStaticFunctions("StringUtils", StringUtils.class);
        AviatorEvaluator.compile("let res=StringUtils.isEmpty('');println(res)").execute();
        AviatorEvaluator.compile("let str='abc';let res=StringUtils.isEmpty(str);println(res)").execute();
    }

    /**
     * 导入java实例方法
     */
    @Test
    public void test03() throws Exception {
        AviatorEvaluator.addInstanceFunctions("String", String.class);
        String str = "abc";
        String res = str.toUpperCase();
        String res2 = str.substring(1, 2);
        AviatorEvaluator.compile("let str='abc';let res=String.indexOf(str,'b');println(res);").execute();
        //instance.method(args) ==> namespace.method(instance, args)
        AviatorEvaluator.compile("let str='abc';let res=String.toUpperCase(str);println(res);").execute();
        AviatorEvaluator.compile("let str='abc';let res=String.toUpperCase(str);println(res);").execute();
        AviatorEvaluator.compile("let str='abc';let res=str.join(seq.array(java.lang.String, '1', '2'));println(res);").execute();
    }

    @Test
    public void test04() throws Exception{
        AviatorEvaluator.setFunctionMissing(new TestFunctionMissing());
        AviatorEvaluator.addInstanceFunctions("StrUtils", StrUtils.class);
        //instance.method(args) ==> namespace.method(instance, args)
        AviatorEvaluator.compile("let str='abc';let utils=new aviator.StrUtils();" +
                "let res=StrUtils.is_empty(utils,str);println(res);").execute();
        AviatorEvaluator.compile("let str='abc';let utils=new aviator.StrUtils();" +
                "let res=StrUtils.isEmpty(utils,str);println(res);").execute();
        AviatorEvaluator.compile("let utils=new aviator.StrUtils();" +
                "let res=StrUtils.test(utils,1,2);println(res);").execute();
    }

    @Test
    public void test05() throws Exception{
        // 启用基于反射的方法查找和调用 将 method(instance, args...) ==> instance.method(args...)
        AviatorEvaluator.setFunctionMissing(JavaMethodReflectionFunctionMissing.getInstance());
        // 调用 String#indexOf
        System.out.println(AviatorEvaluator.execute("indexOf('hello world', 'w')"));
        // 调用 Long#floatValue
        System.out.println(AviatorEvaluator.execute("floatValue(3)"));
        // 调用 BigDecimal#add
        System.out.println(AviatorEvaluator.execute("add(3M, 4M)"));
    }

    /**
     * 找不到函数兜底实现
     */
    private class TestFunctionMissing implements FunctionMissing {

        @Override
        public AviatorObject onFunctionMissing(final String name, final Map<String, Object> env,
                                               final AviatorObject... args) {
            // Returns the function name.
            System.out.println(
                    "Function not found, name=" + name + ", env=" + env + ", args=" + Arrays.toString(args));
            return FunctionUtils.wrapReturn(name);
        }

    }

    @Test
    public void test06(){
        //数组
        AviatorEvaluator.compile("let array=seq.array(int, 1);println(count(array));println(array[0]);for x in array {println(x)};").execute();
        log.info("----------");
        //链表
        AviatorEvaluator.compile("let list=seq.list(1,'a');for x in list {println(x)};").execute();
        log.info("----------");
        //Map
        AviatorEvaluator.compile("let map=seq.map('a','1','b',2,'3','c');println(map);" +
                "for x in map {" +
                "println(x.key + '=' + x.value);" +
                "};" +
                "map.a='11';println(map.a);" +
                "seq.put(map, 'd', 44);println(seq.get(map, 'd'));")
                .execute();
        log.info("----------");
        //不重复集合Set
        AviatorEvaluator.compile("let set=seq.set(1,'a',true,1);println(set);" +
                "for x in set {println(x)};" +
                "println(include(set, 1));").execute();
    }

    @Test
    public void test07(){
        /**
         * fn reduce(seq, fn, init) {
         *   let result = init;
         *   for element in seq {
         *     result = fn(result, element);
         *   }
         *   return result;
         * }
         */
        AviatorEvaluator.compile("println(count('abc'))").execute();
        AviatorEvaluator.compile("let n = seq.list(\"car\", \"bus\", \"bike\");" +
                "let len = reduce(n, lambda(len, x) -> len  + count(x) end, 0);" +
                "println(\"total string length in list is: \" + len);").execute();
    }

    /**
     * 自定义模块
     */
    @Test
    public void test08() throws Exception {
        AviatorEvaluator.getInstance().addModule(StringModule.class);
        String script = "let str = require('sm'); str.isBlank(s) ";
        System.out.println(AviatorEvaluator.execute(script, AviatorEvaluator.newEnv("s", "hello")));
        System.out.println(AviatorEvaluator.execute(script, AviatorEvaluator.newEnv("s", " ")));
        System.out.println(AviatorEvaluator.execute(script, AviatorEvaluator.newEnv("s", null)));
    }

    @Import(ns = "sm")
    public static class StringModule {
        public static boolean isBlank(final String s) {
            return s == null || s.trim().length() == 0;
        }
    }

    @Test
    public void test09(){
        String script = "if(accessNo != nil){\n" +
                "    if(fullName){\n" +
                "        if(string.contains(accessNo,':') && string.contains(accessNo,'@')){\n" +
                "            return accessNo;\n" +
                "        } else {\n" +
                "            return 'sip:'+accessNo+'@botplatform.rcs.vnet.cn';\n" +
                "        }\n" +
                "    } else {\n" +
                "        if(string.contains(accessNo,':') && string.contains(accessNo,'@')){\n" +
                "            return string.substring(accessNo,(string.indexOf(accessNo,':') + 1),string.indexOf(accessNo,'@'));\n" +
                "        } else {\n" +
                "            return accessNo;\n" +
                "        }\n" +
                "    }\n" +
                "} else {\n" +
                "    let accessNo = num + 1;\n" +
                "    return 'sip:'+prefix+accessNo+'@botplatform.rcs.vnet.cn';\n" +
                "}";
        Map<String, Object> m = new HashMap<>();
        String prefix = "10659885862500000301";
        Integer num = -1;
        m.put("prefix", prefix);
        m.put("num", num);
        m.put("fullName", true);
        m.put("accessNo", "sip:106598858625000003011@botplatform.rcs.vnet.cn");
        Object execute = AviatorEvaluator.getInstance().compile(script).execute(m);
        System.out.println(execute.toString());
    }

    @Test
    public void test10(){
        Object execute = AviatorEvaluator.getInstance().compile("cmp('001', '010')").execute();
        System.out.println(execute.toString());
    }

    @Test
    public void test14(){
        Map<String, Object> m = new HashMap<>();
        m.put("max", "9");
        m.put("min", "0");
        Object execute = AviatorEvaluator.getInstance().compile("let n = long(max);return n + 1;").execute(m);
        System.out.println(execute.toString());
    }

    @Test
    public void test13(){
        Object execute = AviatorEvaluator.getInstance().compile("let num = long(1);return string.length(str(num));").execute();
        System.out.println(execute.toString());
    }


    @Test
    public void test11(){
        Object execute = AviatorEvaluator.getInstance().compile("use java.text.DecimalFormat;\n" +
                "DecimalFormat df = new DecimalFormat();\n" +
                "df.setMinimumIntegerDigits(3);\n" +
                "df.setMaximumIntegerDigits(3);\n" +
                "return df.format(1);").execute();
        System.out.println(execute.toString());
    }

    @Test
    public void test12(){
        Date date = new Date();
        date.getTime();
        Object execute = AviatorEvaluator.getInstance().compile("use java.util.Date;\n" +
                "\n" +
                "let d = new Date();\n" +
                "return d.getTime();").execute();
        System.out.println(execute.toString());
    }


    /**
     * 字符串+1方法，该方法将其结尾的整数+1,适用于任何以整数结尾的字符串,不限格式，不限分隔符。
     * @author zxcvbnmzb
     * @param testStr 要+1的字符串
     * @return +1后的字符串
     * @exception NumberFormatException
     */
    public static String addOne(String testStr){
        String[] strs = testStr.split("[^0-9]");//根据不是数字的字符拆分字符串
        String numStr = strs[strs.length-1];//取出最后一组数字
        if(numStr != null && numStr.length()>0){//如果最后一组没有数字(也就是不以数字结尾)，抛NumberFormatException异常
            int n = Integer.valueOf(numStr.length());//取出字符串的长度
            Long num = Long.parseLong(numStr)+1;//将该数字加一
            String added = String.valueOf(num);
            n = Math.min(n, added.length());
            //拼接字符串
            return testStr.subSequence(0, (testStr.length()-n))+added;
        }else{
            throw new NumberFormatException();
        }
    }


}

